#pragma once
#include <memory>
#include <cstring>
#include "socket.hpp"
#include "reactor.hpp"
#include "connection.hpp"
#include "epoller.hpp"
#include "hander_connection.hpp"
#include "noblock.hpp"

/*
    监听模块：负责获取新到来的tcp链接，并将链接形成connection对象添加到reactor中，这个过程会用到connection模块和hander_connection两个模块
    模块的acceptFd函数作为listen形成的connection对象的注册函数使用
*/

class Listener
{
public:
    Listener(const uint16_t port, HanderConnection handercon, const uint32_t addr = INADDR_ANY)
        :_listensocket(make_unique<socket_ns::TcpSocket>()),
        _handercon(handercon)
    {
        // 1、创建套接字通信地址并绑定
        struct sockaddr_in localaddr;
        memset(&localaddr, 0, sizeof(localaddr));
        localaddr.sin_family = AF_INET;
        localaddr.sin_addr.s_addr = addr;
        localaddr.sin_port = htons(port);
        _listensocket->buildServerSocket((struct sockaddr*)&localaddr);
        setNoBlock(_listensocket->getsockfd()); //设置文件描述为非阻塞
        LOG(INFO, "listen socket create success, fd:%d\n", _listensocket->getsockfd());
    }

    void acceptFd(Connection *cnt) // 此方法会被作为监听文件描述符的revcer方法注册到reactor中
    {
        while (true) // 当监听文件描述符读事件就绪，可能有多个新链接到来，所有要一直获取
        {
            struct sockaddr_in srcaddr;
            int code = 0;
            int newfd = _listensocket->Accept(&srcaddr, code);
            if (newfd >= 0)
            {
                // 1、将文件描述符添加到reactor中
                cnt->_reactor->addConnection(newfd, EPOLLIN | EPOLLET, 
                    std::bind(&HanderConnection::recver, &_handercon, std::placeholders::_1),
                    std::bind(&HanderConnection::sender, &_handercon, std::placeholders::_1),
                    std::bind(&HanderConnection::excepter, &_handercon, std::placeholders::_1));
                setNoBlock(newfd); //设置文件描述为非阻塞
            }
            else
            {
                if(code == EWOULDBLOCK || code == EAGAIN)
                {
                    LOG(INFO, "accept all link!\n");
                    break;
                }
                else if(code == EINTR)
                {
                    LOG(INFO, "accept signal!\n");
                    continue;
                }
                else
                {
                    LOG(FATAL, "accept error!\n");
                    break;
                }
            }
        }
    }

    int getListenFd()
    {
        return _listensocket->getsockfd();
    }

private:
    std::unique_ptr<socket_ns::Socket> _listensocket; // 监听套接字
    HanderConnection _handercon; // 含有给普通套接字注册的回调方法(IO+上层业务处理)
};